using System;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace LunoCode.Render
{
	class Camera
	{
		#region fields
		protected Vector3 position;
		protected Vector3 direction;
		int mouseX = LunoGame.Width / 2;
		int mouseY = LunoGame.Height / 2;
		bool locked = false;
		#endregion
		#region Properties
		public Vector3 Position
		{
			get { return position; }
			set { position = value; }
		}

		public Vector3 Direction
		{
			get { return direction; }
			set { direction = value; }
		}
		#endregion

		public Camera(Vector3 position, Vector3 direction)
		{
			this.position = position;
			this.direction = direction;
			direction.Normalize();
		}

		public void MoveForward(float delta)
		{
			position = position + direction * delta;
		}

		Matrix vpCache;

		public Matrix Proj
		{
			get
			{
				return Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45),
																(float)LunoGame.Width / (float)LunoGame.Height,
																1,
																5e5f);
			}
		}

		public Matrix View
		{
			get
			{
				Debug.WriteLine(String.Format("Position x:{0} y:{1} z:{2}\nDirection x:{3} y:{4} z:{5}", 
					position.X, position.Y, position.Z, direction.X, direction.Y, Direction.Z));
				return Matrix.CreateLookAt(Position, Position + Direction, Vector3.Up);
			}
		}


		public void StrafeLeft(float delta)
		{
			Vector3 strafe = new Vector3(-direction.Z, 0, direction.X);
            position -= strafe * delta;
		}

		public void MoveUp(float delta)
		{
			position.Y += delta;
		}

		public void Input()
		{
			if (locked)
				return;
			KeyboardState keyboard = Keyboard.GetState();

			if (keyboard.IsKeyDown(Keys.W))
			{
				this.MoveForward(200);
			}
			if (keyboard.IsKeyDown(Keys.S))
			{
				this.MoveForward(-200);
			}
			if (keyboard.IsKeyDown(Keys.A))
			{
				this.StrafeLeft(200);
			}
			if (keyboard.IsKeyDown(Keys.D))
			{
				this.StrafeLeft(-200);
			}
            
			MouseState mouseState = Mouse.GetState();
			float deltaX = (mouseState.X - mouseX) / (float)250;
			float deltaY = -(mouseState.Y - mouseY) / (float)250;
			if ((Math.Abs(deltaY) > float.Epsilon) || (Math.Abs(deltaX) > float.Epsilon))
			{
				float x1 = direction.X;
				float y1 = direction.Z;
				float z1 = direction.Y;
				float len = (float)Math.Sqrt(x1*x1+y1*y1);
				float resX = (float)(Math.Cos(Math.Atan2(y1, x1) + deltaX) * len);
				float resZ = (float)Math.Sin(Math.Atan2(y1, x1) + deltaX) * len;

				x1 = resX;
				y1 = resZ;
				len = (float)Math.Sqrt(x1 * x1 + y1 * y1);
				float len2 = (float)Math.Sqrt(len * len + z1 * z1);
				float len2_2 = (float)Math.Cos(Math.Atan2(z1, len) + deltaY) * len2;
				float resY = (float)Math.Sin(Math.Atan2(z1, len) + deltaY) * len2;
				resX = x1 * len2_2 / len;
				resZ = y1 * len2_2 / len;

				Vector3 moved = new Vector3(resX, resY, resZ);
				moved.Normalize();

				if (Math.Abs(Vector3.Dot(moved, Vector3.Up)) < 0.98f)
					direction = moved;
			}
			Mouse.SetPosition(LunoGame.Width / 2, LunoGame.Height / 2);
		}
	}
}